package com.zero.execute.writer;

import com.zero.common.Common;
import com.zero.common.MysqlTypeMapEnum;
import com.zero.core.ZeroContext;
import com.zero.db.MysqlJdbc;
import com.zero.util.BaseUtil;
import com.zero.util.CamelCaseUtil;
import com.zero.util.FreemarkerUtils;
import com.zero.xmodel.definition.AttrDefinition;
import com.zero.xmodel.definition.EntityDefinition;
import com.zero.xmodel.definition.TableColumnDefinition;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * entity生成器
 *
 * @author wuxi
 * @date 2020-07-28
 */
public class EntityWriter implements Writer {

    private ZeroContext context;

    public EntityWriter(ZeroContext context) {
        this.context = context;
    }

    @Override
    public void create() {
        //todo 支持多种数据库：通过驱动适配
        MysqlJdbc mysqlJdbc = new MysqlJdbc(context.getJdbcConfigPO());
        //获取表名
        getTableName(mysqlJdbc);
        //加入容器
        Map<String, EntityDefinition> entityMap = new HashMap<>(context.getTableNames().size());
        for (String tableName : context.getTableNames()) {
            List<TableColumnDefinition> columnsTableList = mysqlJdbc.executeToList("SHOW FULL COLUMNS FROM " + tableName, null,
                    TableColumnDefinition.class);
            if (null == columnsTableList || columnsTableList.size() == 0) {
                throw new RuntimeException(tableName + "表信息不存在！");
            }
            //开始创建文件
            generateEntity(tableName, columnsTableList, entityMap);
        }
        this.context.setEntityMap(entityMap);
        mysqlJdbc.close();
    }

    /**
     * 当没有配置表名的时候，就获取全部
     *
     * @param mysqlJdbc mysqlJdbc
     */
    private void getTableName(MysqlJdbc mysqlJdbc) {
        if (null == this.context.getTableNames() || this.context.getTableNames().size() == 0) {
            List<String> tables = mysqlJdbc.executeToList("show tables");
            this.context.setTableNames(tables);
        }
    }

    /**
     * 生成entity
     *
     * @param tableName        表名
     * @param columnsTableList 内容
     */
    private void generateEntity(String tableName, List<TableColumnDefinition> columnsTableList, Map<String, EntityDefinition> entityMap) {
        EntityDefinition po = builderEntity(tableName, columnsTableList);
        Map<String, Object> data = new HashMap<>(1);
        //使用模板
        data.put("po", po);
        FreemarkerUtils.getTemplate(this.context.getFreemarkerTemplateMap().get("entityTemplate"),
                data,
                this.context.getPackagePO().getEntityPackageName() + Common.separator_file_ios + po.getClassName(),
                this.context.getSeparator());
        entityMap.put(po.getClassName(), po);
    }

    /**
     * 构建Entity对象
     *
     * @param tableName        表名
     * @param columnsTableList 字段数据
     */
    private EntityDefinition builderEntity(String tableName, List<TableColumnDefinition> columnsTableList) {
        EntityDefinition entity = new EntityDefinition();
        entity.setPackageName(BaseUtil.parsingPackage(this.context.getPackagePO().getEntityPackageName(),
                this.context.getSeparator()));
        if (!StringUtils.isEmpty(this.context.getPreTable())) {
            tableName = tableName.replace(this.context.getPreTable(), "");
        }
        entity.setTableName(tableName);
        entity.setClassName(CamelCaseUtil.convertToCamelCaseByClass(tableName) + "PO");
        //构建属性对象
        builderAttr(columnsTableList, entity);
        return entity;
    }

    /**
     * 构建属性对象
     *
     * @param columnsTableList 表解析参数
     */
    private void builderAttr(List<TableColumnDefinition> columnsTableList, EntityDefinition entity) {
        Set<String> importNames = new HashSet<>();
        List<AttrDefinition> attrList = columnsTableList.parallelStream().map(t -> {
            AttrDefinition attr = new AttrDefinition();
            attr.setComment(t.getComment());
            attr.setDbName(t.getField());
            attr.setName(CamelCaseUtil.convertToCamelCase(t.getField()));
            String dbType = t.getType().replaceAll("[(].*.$", "");
            //db类型 映射到 java 类型
            MysqlTypeMapEnum mapEnum = MysqlTypeMapEnum.getType(dbType);
            String type = mapEnum.getJavaType();
            if (MysqlTypeMapEnum.specialTypeMap.contains(type)) {
                importNames.add(mapEnum.getJavaTypeClass());
            }
            attr.setType(type);
            return attr;
        }).collect(Collectors.toList());
        entity.setAttrs(attrList);
        entity.setImportNames(importNames);
    }
}